import {useVueFlow} from '@vue-flow/core'
import {ref, watch} from 'vue'
import {nextId} from '@/utils/common/snowflakeIdGenerator.js';


/**
 * In a real world scenario you'd want to avoid creating refs in a global scope like this as they might not be cleaned up properly.
 * @type {{draggedType: Ref<string|null>, isDragOver: Ref<boolean>, isDragging: Ref<boolean>}}
 */
const state = {
    /**
     * The type of the node being dragged.
     */
    draggedType: ref(null),
    isDragOver: ref(false),
    isDragging: ref(false),
    draggedConfig: ref({}),
}

export default function useDragAndDrop() {
    const {draggedType, isDragOver, draggedConfig, isDragging} = state

    const {addNodes, screenToFlowCoordinate, onNodesInitialized, updateNode} = useVueFlow()

    watch(isDragging, (dragging) => {
        document.body.style.userSelect = dragging ? 'none' : ''
    })

    function onDragStart(event, node) {
        console.log('onDragStart', event, node)
        if (event.dataTransfer) {
            event.dataTransfer.setData('application/vueflow', node.type)
            event.dataTransfer.effectAllowed = 'move'
        }

        draggedType.value = node.type
        isDragging.value = true
        draggedConfig.value = node.defaultConfig ?? {},

            document.addEventListener('drop', onDragEnd)
    }

    // 双击时触发的事件处理函数
    const onClick = ( event,node
    ) => {
        console.log('onDoubleClick', event, node)
        if (event.dataTransfer) {
            event.dataTransfer.setData('application/vueflow', node.type)
            event.dataTransfer.effectAllowed = 'move'
        }
        draggedType.value = node.type
        isDragging.value = true
        draggedConfig.value = node.defaultConfig ?? {}

        // 模拟 drop 操作
        const fakeDropEvent = {
            clientX: event.clientX,
            clientY: event.clientY-400
        };
        onDrop(fakeDropEvent);

        document.addEventListener('drop', onDragEnd)
    };

    /**
     * Handles the drag over event.
     *
     * @param {DragEvent} event
     */
    function onDragOver(event) {
        event.preventDefault()
        if (draggedType.value) {
            isDragOver.value = true

            if (event.dataTransfer) {
                event.dataTransfer.dropEffect = 'move'
            }
        }
    }

    function onDragLeave() {
        isDragOver.value = false
    }

    function onDragEnd() {
        isDragging.value = false
        isDragOver.value = false
        draggedType.value = null
        document.removeEventListener('drop', onDragEnd)
    }

    /**
     * Handles the drop event.
     *
     * @param {DragEvent} event
     */
    function onDrop(event) {
        const position = screenToFlowCoordinate({
            x: event.clientX,
            y: event.clientY,
        })

        const nodeId = nextId();

        const newNode = {
            id: nodeId,
            type: draggedType.value,
            position,
            data: JSON.parse(JSON.stringify(draggedConfig.value)),
        }

        /**
         * Align node position after drop, so it's centered to the mouse
         *
         * We can hook into events even in a callback, and we can remove the event listener after it's been called.
         */
        const {off} = onNodesInitialized(() => {
            updateNode(nodeId, (node) => ({
                position: {x: node.position.x - node.dimensions.width / 2, y: node.position.y - node.dimensions.height / 2},
            }))

            off()
        })

        addNodes(newNode)
    }

    return {
        draggedType,
        isDragOver,
        isDragging,
        onDragStart,
        onDragLeave,
        onDragOver,
        onDrop,
        onClick
    }
}